;
; cpu.asm
;
; Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU Affero General Public License as
; published by the Free Software Foundation, either version 3 of the
; License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU Affero General Public License for more details.
;
; You should have received a copy of the GNU Affero General Public License
; along with this program.  If not, see <http://www.gnu.org/licenses/>.
;

CPU_FEATURE_FPU         EQU 1 << 0
CPU_FEATURE_VME         EQU 1 << 1
CPU_FEATURE_DE          EQU 1 << 2
CPU_FEATURE_PSE         EQU 1 << 3
CPU_FEATURE_TSC         EQU 1 << 4
CPU_FEATURE_MSR         EQU 1 << 5
CPU_FEATURE_PAE         EQU 1 << 6
CPU_FEATURE_MCE         EQU 1 << 7
CPU_FEATURE_CX8         EQU 1 << 8
CPU_FEATURE_APIC        EQU 1 << 9
CPU_FEATURE_SEP         EQU 1 << 11
CPU_FEATURE_MTRR        EQU 1 << 12
CPU_FEATURE_PGE         EQU 1 << 13
CPU_FEATURE_MCA         EQU 1 << 14
CPU_FEATURE_CMOV        EQU 1 << 15
CPU_FEATURE_PAT         EQU 1 << 16
CPU_FEATURE_PSE36       EQU 1 << 17
CPU_FEATURE_PSN         EQU 1 << 18
CPU_FEATURE_CLFL        EQU 1 << 19
CPU_FEATURE_DTES        EQU 1 << 21
CPU_FEATURE_ACPI        EQU 1 << 22
CPU_FEATURE_MMX         EQU 1 << 23
CPU_FEATURE_FXSR        EQU 1 << 24
CPU_FEATURE_SSE         EQU 1 << 25
CPU_FEATURE_SSE2        EQU 1 << 26
CPU_FEATURE_SS          EQU 1 << 27
CPU_FEATURE_HTT         EQU 1 << 28
CPU_FEATURE_TM1         EQU 1 << 29
CPU_FEATURE_IA64        EQU 1 << 30
CPU_FEATURE_PBE         EQU 1 << 31

bits 32

global cpu_init
global fpu_save
global fpu_restore
global cpu_vendor
global cpu_features

cpu_vendor:   times 16  DB 0
cpu_features: times 2   DD 0

;********************************************************************************
; void cpu_init(void)
;********************************************************************************
cpu_init:               push ebp
                        mov ebp, esp
                        sub esp, 4
.fpu_check:             mov eax, cr0
                        and eax, 0xFFFFFFF3
                        or eax, 0x20
                        mov cr0, eax
                        fninit
                        mov word [ebp - 4], 0xCCCC
                        fnstsw word [ebp - 4]
                        cmp word [ebp - 4], 0
                        jnz .cpuid_check
                        or byte [cpu_features], 1
.cpuid_check:           pushfd
                        pop eax
                        xor eax, 0x200000
                        push eax
                        popfd
                        pushfd
                        pop edx
                        cmp eax, edx
                        jnz .no_cpuid
                        xor eax, eax
                        push ebx
                        cpuid
                        mov dword [cpu_vendor], ebx
                        mov dword [cpu_vendor + 4], edx
                        mov dword [cpu_vendor + 8], ecx
                        mov eax, 1
                        cpuid
                        mov dword [cpu_features], edx
                        mov dword [cpu_features + 4], ecx
                        pop ebx
.no_cpuid:              leave
                        ret

;********************************************************************************
; void fpu_save(byte_t *buffer)
;********************************************************************************
fpu_save:               push ebp
                        mov ebp, esp
                        sub esp, 512 + 16
                        push esi
                        push edi
                        lea esi, [ebp - 512]
                        and esi, 0xFFFFFFF0
                        mov edi, [ebp + 8]
                        test dword [cpu_features], CPU_FEATURE_FXSR
                        jz .no_fxr
                        fxsave [esi]
                        mov ecx, 128
                        jmp .copy
.no_fxr:                fsave [esi]
                        mov ecx, 27
.copy:                  cld
                        rep movsd
                        pop edi
                        pop esi
                        xor eax, eax
                        leave
                        ret

;********************************************************************************
; void fpu_restore(byte_t *buffer)
;********************************************************************************
fpu_restore:            push ebp
                        mov ebp, esp
                        sub esp, 512 + 16
                        push esi
                        push edi
                        mov esi, [ebp + 8]
                        lea edi, [ebp - 512]
                        and edi, 0xFFFFFFF0
                        mov eax, edi
                        cld
                        test dword [cpu_features], CPU_FEATURE_FXSR
                        jz .no_fxr
                        mov ecx, 128
                        rep movsd
                        fxrstor [eax]
                        jmp .done
.no_fxr:                mov ecx, 27
                        rep movsd
                        frstor [eax]
.done:                  pop edi
                        pop esi
                        xor eax, eax
                        leave
                        ret
